/*基环树DP
    基环树:由一个环和若干棵树组成。
           基环树是在一棵树上添加一条边，使得图中恰好形成一个环
    内向树的所有边都是指向根节点方向的
    外向树的所有边都从根节点指向其他节点

* 1.对于一棵基环树，如何快速求出任意两个点之间距离的最大值
    可以将所有点对分成两类，
    一类是两个点属于同一棵子树，则此时这两个点的路径只会用到子树内的边，不会用到环上的边，
    这样就是单纯在一棵树内求任意两个点之间距离的最大值也就是求树的直径，
    可以用树形dp来求，枚举子树上所有点作为最高点，求出向下走的最长路和次长路，就是经过当前点的直径，枚举所有点取一个最大值就是整棵子树的直径。
    
    另一类就是两个点不属于同一棵子树，此时这两个点之间的路径必然会经过环，
    我们可以将路径分成三部分，一部分是环上的路径，另外两部分是环上任意两个点往下走的路径，
    由于要求最大距离，因此这三部分都要尽可能的大，而环上每个点往下走的最长距离一定是固定的，
    因此我们可以预处理一下环上每个点往下走的最长距离 dist[i]，
    然后枚举环上任意两个点 a,b，此时这条路径应该是 dist[a]+dist[b]+S(a,b)
    其中S(a,b)表示a, b之间的最长距离。

* 2.S(a, b) == S(b, a)
    枚举一种方向，设a在b的顺时针方向上
    枚举a，即可枚举到环上所有的情况
    此时对于任意的a，需要在环上找到一个b，使得dist[a]+dist[b]+S(a,b)最大
    由于S(a,b)是一个区间和，预处理前缀和，设S[x]为顺时针方向前缀和，此时路径长度变为dist[a]+dist[b]+S[a]-S[b]
    此时a是固定的，因此dist[a]+S[a]是固定的，只需要求dist[b]-S[b]的最大值
    断环成链，z在将链复制接在其后，每次枚举链上长度为原环长度的区间，都是环上的一种情况
    在任意一种情况上取dist[b]-S[b]的最大值->滑动窗口求最值问题

* 3.dfs()找环
    用栈记录递归路径，找到路径中某点，则找到环

* 本题:
    在基环森林中选出若干个点，使得任意两个点没有公共边，要求选出的最大点权和
    f[u][0]在以u为根的子树中选若干个点且不选u的所有方案的最大值
    f[u][1]在以u为根的子树中选若干个点且选u的所有方案的最大值

    转移方程: u的每一个子节点是s
        f[u][0]=∑max(f[s][0], f[s][1]);
        f[u][1]=∑f[s][0]
*/  

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define DEBUG
using ll=long long;
inline int read()
{
	int x=0;char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x;
}
inline void write(ll x)
{
	if (x>=10) write(x/10);
	putchar(x%10+48);
}//快读快输

const int N=1e6+10, INF=0x3f3f3f3f;

int n;
int h[N], e[N], w[N], ne[N], idx;
int rm[N]; //i边是否被删除
bool st[N], in_stack[N];
ll f1[N][2], f2[N][2];
// f[i][0]在以i为根的子树中选若干个点 且不选i的所有方案的最大值
// f[i][1]在以i为根的子树中选若干个点 且选i的所有方案的最大值
ll res=0;

inline void AddEdge(int a, int b) //, int c)
{
    e[idx]=b, ne[idx]=h[a], h[a]=idx++; //w[idx]=c, 
}

void dfs_f(int u, int ap, ll f[][2]) //树形 dp 求以u为根的子树中 不选ap的所有方案的最大值
{
    //不选u
    for(int i=h[u]; ~i; i=ne[i])
    {
        if(rm[i]) continue;
        int v=e[i];
        dfs_f(v, ap, f);
        f[u][0]+=max(f[v][0], f[v][1]);
    }

    //选u
    f[u][1]=-INF; //如果u不可选，则f[u][1]不可有任何有效选值
    if(u!=ap) //u可以选
    {
        f[u][1]=w[u];
        for(int i=h[u]; ~i; i=ne[i])
        {
            if(rm[i]) continue;
            int v=e[i];
            f[u][1]+=f[v][0];
        }
    }
}

void dfsCircle(int u, int from) //找出所有环 当前节点 从哪条边来的
{
    st[u]=in_stack[u]=true;
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(!st[v]) dfsCircle(v, i);
        else if(in_stack[v]) //找到环
        {
            rm[i]=true; //删除u->v
            dfs_f(v, -1, f1); //不选v
            dfs_f(v, u, f2); //选v不选u
            res+=max(f1[v][0], f2[v][1]); //累加上两种情况的最大值
        }
    }
    in_stack[u]=false; //弹出
}

void solve()
{
    memset(h, -1, sizeof h);

    n=read();
    
    for(int i=1; i<=n; i++)
    {
        int a=read(), b=read();
        AddEdge(b, i); w[i]=a;
    }
    //找出基环树的环
    for(int i=1; i<=n; i++)
        if(!st[i])
            dfsCircle(i, -1);

    
    printf("%lld\n", res);
}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
        freopen("./out.txt","w",stdout);
    #endif

    
    int T=1; //T=read();
    while(T--)
    {
        solve();
    }
    return 0;
}